/*
 * Created on 2008-06-04
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package elka.isi.util;

import elka.isi.gene.AnimalGene;
import elka.isi.individual.AnimalIndividual;
import elka.isi.individual.RabbitIndividual;
import elka.isi.individual.RoeIndividual;
import elka.isi.individual.WolfIndividual;
import org.evolvica.core.*;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * @author jurek
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class RWUtils {
	
	/**
	 * variables used to set column to print in stats
	 * array to set order and which columns to print
	 * location of output file
	 */
	private final static String STATS_SEPARATOR = "\t";
	private static boolean beenWriting = false;
	public final static int RABBITS_SIZE_COLUMN = 0;
	public final static int WOLVES_SIZE_COLUMN = 1;
    public final static int ROES_SIZE_COLUMN = 2;
    public final static int RABBITS_FIGHT_AVERAGE_COLUMN = 3;
	public final static int WOLVES_FIGHT_AVERAGE_COLUMN = 4;
	public final static int COUNTER_COLUMN = 5;
	public static int[] statsToPrint;
	public static String outputFileLocation = null;
	
	private static int rowsCounter = 0;

	/**
	 *  result null if no wolves 
	 */
	public static IIndividualSet getWolves(IIndividualSet set) {
    	IndividualList result = new IndividualList();
    	for (ISetIterator it = ((IIndividualSet) set).iterator(); it.hasNext(); ) {
    		AnimalIndividual individual = (AnimalIndividual) it.next();
    		switch (individual.getSpecies()) {
			case AnimalIndividual.WOLF:
				result.add(individual);
				break;
    		}
        }
		return result;
	}

	/**
	 * result null if no rabbits 
	 */
	public static IIndividualSet getRabbits(IIndividualSet set) {
    	IndividualList result = new IndividualList();
    	for (ISetIterator it = ((IIndividualSet) set).iterator(); it.hasNext(); ) {
    		AnimalIndividual individual = (AnimalIndividual) it.next();
    		switch (individual.getSpecies()) {
			case AnimalIndividual.RABBIT:
				result.add(individual);
				break;
    		}
        }
		return result;
	}

    public static IIndividualSet getRoes(IIndividualSet set) {
    	IndividualList result = new IndividualList();
    	for (ISetIterator it = ((IIndividualSet) set).iterator(); it.hasNext(); ) {
    		AnimalIndividual individual = (AnimalIndividual) it.next();
    		switch (individual.getSpecies()) {
			case AnimalIndividual.ROE:
				result.add(individual);
				break;
    		}
        }
        return result;
    }
    
    public static IIndividualSet getHerbivores(IIndividualSet set){
    	IndividualList result = new IndividualList();
    	for (ISetIterator it = ((IIndividualSet) set).iterator(); it.hasNext(); ) {
    		AnimalIndividual individual = (AnimalIndividual) it.next();
    		switch (individual.getSpecies()) {
			case AnimalIndividual.RABBIT:
				result.add(individual);
				break;

			case AnimalIndividual.ROE:
				result.add(individual);
				break;

			default:
				break;
			}
    	}
    	return result;
    }
	/**
	 * printing whole of the population
	 * @param set - population to print
	 */
	public static void printIndividualSet(IIndividualSet set) {
		IIndividual individual;
		for (ISetIterator it = ((IIndividualSet) getRabbits(set)).iterator();
			it.hasNext();
			) {
			individual = (IIndividual) it.next();
			System.out.println(
				"rabbit: "
					+ individual.getGenotype().toString()
					+ " "
					+ individual.getScore());
		}
        for (ISetIterator it = ((IIndividualSet) getRoes(set)).iterator();
			it.hasNext();
			) {
			individual = (IIndividual) it.next();
			System.out.println(
				"roe: "
					+ individual.getGenotype().toString()
					+ " "
					+ individual.getScore());
		}
		for (ISetIterator it = ((IIndividualSet) getWolves(set)).iterator();
			it.hasNext();
			) {
			individual = (IIndividual) it.next();
			System.out.println(
				"wolf: "
					+ individual.getGenotype().toString()
					+ " "
					+ individual.getScore());
		}
	}
	
	/**
	 * print stats of genotypes
	 * @param set
	 */
    public static void printStats(IIndividualSet set) {

        printAnimals(getRabbits(set), "Rabbits");
        printAnimals(getRoes(set), "Roes");
        printAnimals(getWolves(set), "Wolves");

    }

    private static void printAnimals(IIndividualSet animals, String speciesName) {
        List result = new ArrayList();

        int[] results = new int[animals.size()];
        IIndividual individual;
        System.out.println(speciesName + ": " + animals.size());

        for (ISetIterator it = animals.iterator(); it.hasNext(); ) {
            individual = it.next();

            AnimalGene animalGene = (AnimalGene) individual.getGenotype();
            int[] geneValue = animalGene.getValue();

            if (!result.contains(geneValue)) {
                result.add(geneValue);
            }

            results[result.indexOf(geneValue)]++;
        }
        for (int i = 0; i < result.size(); i++) {
            System.out.println(
                    "genotype: "
                            + Arrays.toString((int[]) result.get(i))
                            + " was "
                            + results[i]
                            + " times");
        }
    }

    /**
	 * helper to get controlled number of indivuals from the whole set
	 * @param set to choose from
	 * @param amount how many individuals will be choosed
	 * @return choosed indivudals
	 */
	public static IIndividualSet getRandomIndividuals(
		IIndividualSet set,
		int amount) {
		if (amount >= set.size())
			return set;
		else {
			IIndividualSet choosedSet = new IndividualList();
			IIndividual[] clonedSet;
			clonedSet = set.toArray();
			int choosedIndex;
			for (int i = 0; i < amount; i++) {
				Random random = new Random();
				choosedIndex = Math.abs(random.nextInt()) % set.size();
				if (!choosedSet.contains(clonedSet[choosedIndex])) {
					choosedSet.add(clonedSet[choosedIndex]);
				} else
					--i;
			}
			return choosedSet;
		}
	}
	/**
	 * ZIBI's
	 * @param population
	 * @param from
	 * @param comp
	 * @return
	 */
	public static IIndividualSet getWeaker(
		IIndividual[] population,
		IIndividual from,
		IIndividualComparator comp) {
			
		IIndividualSet ret = new IndividualArray();
		for (int i = population.length - 1; i >= 0; i--) {
			if (comp.compare(from, population[i]) < 0)
				ret.add(population[i]);
		}
		return ret;
	}
	
	/**
	 * count fighting score from individual's genotype
	 * point are taken from 1st, 2nd and 3rd position of genotype
	 * genotype must be at least 3 chars long
	 * @param ind
	 * @return fighting score
	 */
	public static int scoreFightAbility(IIndividual ind) 
	{
		return 0;
//		TODO: po zmianie genotypu na int[] trzeba uaktualnic.
//		W ogole to chyba powinno byc w RWEvaluator?

//		if (ind.getGenotype() instanceof AnimalGene) {
//			String gene = ((AnimalGene)ind.getGenotype()).getValue();
//			return (int)gene.charAt( 0 ) + (int)gene.charAt( 1 ) + (int)gene.charAt( 2 );
//		} else	return -1;

	}
	
	/**
	 * count harvesting (like in Dune 2 RTS )
	 * score from individual's genotype
	 * point are taken from 4th, 5th and 6th position of genotype
	 * genotype must be at least 6 chars long
	 * @param ind
	 * @return harvesting score
	 */
	public static int scoreHarvestAbility(IIndividual ind)
	{
		
		return 0;
//		TODO: po zmianie genotypu na int[] trzeba uaktualnic.
//		W ogole to chyba powinno byc w RWEvaluator?

		
//		if (ind.getGenotype() instanceof AnimalGene) {
//			String gene = ((AnimalGene)ind.getGenotype()).getValue();
//			return (int)gene.charAt( 3 ) + (int)gene.charAt( 4 ) + (int)gene.charAt( 5 );
//		} else	return -1;
	}
	
	/**
	 * count reproduction ability
	 * score from individual's genotype
	 * point are taken from 7th, 8th and 9th position of genotype
	 * genotype must be at least 9 chars long
	 * @param ind
	 * @return reproduction ability score
	 */
	public static int scoreReproduceAbility(IIndividual ind)
	{
		return 0;
//		TODO: po zmianie genotypu na int[] trzeba uaktualnic.
//		W ogole to chyba powinno byc w RWEvaluator?

		
//		if (ind.getGenotype() instanceof AnimalGene) {
//			String gene = ((AnimalGene)ind.getGenotype()).getValue();
//			return (int)gene.charAt( 6 ) + (int)gene.charAt( 7 ) + (int)gene.charAt( 8 );
//		} else return -1; 
	}
	
	//todo: niepelne uwzglednienie saren /Jacek
	public static void getActualStats(IIndividualSet set)
	{
		String stringToReturn = "";
		 for(int i=0;i < statsToPrint.length ; i++)
		 {
			IIndividual individual;
			int averageFightScore;
		 	switch(statsToPrint[i])
		 	{
		 		case COUNTER_COLUMN:
		 			stringToReturn += (rowsCounter++)+STATS_SEPARATOR;
		 			break;
		 		case RABBITS_SIZE_COLUMN:
					stringToReturn += (RWUtils.getRabbits(set)).size()+STATS_SEPARATOR;
					break;
				case WOLVES_SIZE_COLUMN:
					stringToReturn += (RWUtils.getWolves(set)).size()+STATS_SEPARATOR;
					break;
                case ROES_SIZE_COLUMN:
                    stringToReturn += (RWUtils.getRoes(set)).size()+STATS_SEPARATOR;
                    break;
                case RABBITS_FIGHT_AVERAGE_COLUMN:
					averageFightScore = 0;
					if(RWUtils.getRabbits(set).size() == 0)
					{
						stringToReturn += averageFightScore+STATS_SEPARATOR;
						break;
					}
					for (ISetIterator it = ((IIndividualSet) getRabbits(set)).iterator();
						it.hasNext();) {
						individual = (RabbitIndividual) it.next();
						averageFightScore += ((AnimalIndividual) individual).getHuntingScore();
					}
					averageFightScore /= RWUtils.getRabbits(set).size();
					stringToReturn += averageFightScore+STATS_SEPARATOR;
					break;
				case WOLVES_FIGHT_AVERAGE_COLUMN:
					averageFightScore = 0;
				if(RWUtils.getWolves(set).size() == 0)
				{
					stringToReturn += averageFightScore+STATS_SEPARATOR;
					break;
				}
					for (ISetIterator it = ((IIndividualSet) getWolves(set)).iterator();
						it.hasNext();) {
						individual = (AnimalIndividual) it.next();
						averageFightScore += ((AnimalIndividual) individual).getHuntingScore();
					}
					averageFightScore /= getWolves(set).size();
					stringToReturn += averageFightScore+STATS_SEPARATOR;
					break;								
		 		default:
		 		break; 
		 	}
		 }
		 stringToReturn += "\n";
		 if(outputFileLocation != null)
		 {
			try 
			{
			 	File file = new File(outputFileLocation);
				if(!beenWriting)
				{
					file.delete();
					beenWriting = true; 
				}
				FileWriter fw = new FileWriter(file,true); 
				fw.append(stringToReturn);
		 		fw.close();
			} catch (IOException e) 
			{
				e.printStackTrace();
			} 
		 } else
		 System.out.println(stringToReturn);
	}
}
